package simpleGeom;

public class SegPreCalc {
	HasPos3D p1;
	HasPos3D p2;
	Vec3D v;
	float c2;

	public SegPreCalc(HasPos3D p1, HasPos3D p2) {
	 	this.p1 = p1;
		this.p2 = p2;
		v = Vec3D.sub(p2, p1);
		c2 = Vec3D.dot3D(v, v);
	}

	public float dist_Point_to_Line(float x, float y, float z) {
		Vec3D pt = new Vec3D(x, y, z);
		HasPos3D cP=getClosestPtLine(x,y,z);
		return Vec3D.dist(pt, cP);
	}
	public HasPos3D getClosestPtLine(float x, float y, float z){
		Vec3D pt = new Vec3D(x, y, z);
		Vec3D w = Vec3D.sub(pt, p1);
		float c1 = Vec3D.dot(w, v);
		float b = c1 / c2;
		return Vec3D.add(p1, Vec3D.mult(v, b));
	}
	public HasPos3D getClosestPtSeg(float x, float y, float z){
		Vec3D pt = new Vec3D(x, y, z);
		Vec3D w = Vec3D.sub(pt, p1);
		float c1 = Vec3D.dot(w, v);
		if (c1 <= 0)
			return p1;
		if (c2 <= c1)
			return p2;
		float b = c1 / c2;
		return Vec3D.add(p1, Vec3D.mult(v, b));
	}

	// ===================================================================

	// dist_Point_to_Segment(): get the distance of a point to a segment
	// Input: a Point P and a Segment S (in any dimension)
	// Return: the shortest distance from P to S
	public float dist_Point_to_Segment(float x, float y, float z) {
		Vec3D pt = new Vec3D(x, y, z);
		HasPos3D cP=getClosestPtSeg(x,y,z);
		return Vec3D.dist(pt, cP);
	}
	
	static float minimum_distance(HasPos3D v, HasPos3D w, HasPos3D p) {
		  // Return minimum distance between line segment vw and point p
		   float l2 = Vec3D.distSqr(v, w);  // i.e. |w-v|^2 -  avoid a sqrt
		  if (l2 == 0.0) return Vec3D.dist(p, v);   // v == w case
		  // Consider the line extending the segment, parameterized as v + t (w - v).
		  // We find projection of point p onto the line. 
		  // It falls where t = [(p-v) . (w-v)] / |w-v|^2
		  Vec3D pv=Vec3D.sub(p,v);
		  Vec3D wv=Vec3D.sub(w,v);
		   float t = Vec3D.dot(pv, wv) / l2;
		  if (t < 0.0) return Vec3D.dist(p, v);       // Beyond the 'v' end of the segment
		  else if (t > 1.0) return Vec3D.dist(p, w);  // Beyond the 'w' end of the segment
		  Vec3D proj=Vec3D.add(v, Vec3D.mult(wv, t));
		  //const vec2 projection = v + t * (w - v);  // Projection falls on the segment
		  return Vec3D.dist(p, proj);
		}
	 public float minimum_distance(float x,float y,float z) {
		 HasPos3D p=new Vec3D(x,y,z);
		 
		  return minimum_distance(p1,p2,p);
		}
}
